/*
包功能说明：专门用于格式化打印框架的基础信息（logo、官网、版本）和运行时全局信息（进程ID、运行模式）
核心价值：通过统一的边框样式和ASCII标识，让信息展示更整齐、可视化，提升开发者对框架状态的可读性
*/
package info

import (
	"fmt"             // 用于格式化输出（如打印字符串、拼接内容）
	"gameServer/mode" // 运行模式
	"strings"         // 用于字符串处理（如去除首尾换行、重复空格）
	"syscall"         // 用于调用系统接口（此处用于获取当前进程的PID）
	"unicode/utf8"    // 用于计算UTF-8编码字符串的字符数（支持中文等多字节字符，避免长度计算错误）
)

// logo 定义框架的ASCII艺术字标识
// 作用：作为框架的视觉符号，启动时展示在最上方，增强辨识度
// 内容：通过下划线、斜线构建的多层级图形，模拟立体效果
const logo = `
		   _____     ____  __  ________
           / __  \  / __ \/ / / / ____/	
          / /_/  / / / / / / / / __/
         /  //__/ / /_/ / /_/ / /___
        /  / \  \/_____/\____/_____/
	   /__/   \__\
`

// 以下常量定义信息展示框的样式规则和固定配置
// 作用：统一所有信息框的外观，确保风格一致，避免硬编码导致的格式混乱

const (
	boxWidth          = 56            // 信息框的总宽度（单位：字符），所有框都按此宽度生成，确保整体对齐
	verticalBorder    = "|"           // 信息框的垂直边框字符（左右两侧的竖线）
	horizontalBorder  = "─"           // 信息框的水平边框字符（上下两侧的横线）
	leftTopBorder     = "┌"           // 信息框的左上角边框字符（顶框左上角的拐角）
	rightTopBorder    = "┐"           // 信息框的右上角边框字符（顶框右上角的拐角）
	leftBottomBorder  = "└"           // 信息框的左下角边框字符（底框左下角的拐角）
	rightBottomBorder = "┘"           // 信息框的右下角边框字符（底框右下角的拐角）
	website           = "骗你的其实根本没有网址" // 框架官网地址的占位符（实际使用时需替换为真实地址）
	version           = "v0.1.0"      // 框架当前版本号（用于开发者识别使用的版本）
	global            = "Global"      // 全局信息框的标题标识（区分不同类型的信息框）
)

// PrintFrameworkInfo 打印框架的核心基础信息
// 工作原理：
// 1. 处理ASCII logo：通过strings.TrimPrefix和strings.TrimSuffix去除logo首尾的换行符，避免顶部/底部出现空白行
// 2. 生成信息框：调用PrintBoxInfo函数，生成一个“无标题顶框”的信息框，填入官网和版本信息
// 执行效果：
//   - 屏幕先显示处理后的ASCII艺术字（无多余空白），例如：
//     _____     ____  __  ________
//     / __  \  / __ \/ / / / ____/
//     / /_/  / / / / / / / / __/
//     /  //__/ / /_/ / /_/ / /___
//     /  / \  \/_____/\____/_____/
//     /__/   \__\
//   - 下方紧接着显示一个56字符宽的矩形框，内容如下（左右边框为"|"，内部左对齐，右侧补空格）：
//
// ┌────────────────────────────────────────────────────────────────────────────────┐
// | [Website] 骗你的其实根本没有网址												    |
// | [Version] v0.1.0                                                              	|
// └────────────────────────────────────────────────────────────────────────────────┘
func PrintFrameworkInfo() {
	// 处理logo：去除首尾的"\n"，让logo与下方信息框无缝衔接
	formattedLogo := strings.TrimSuffix(strings.TrimPrefix(logo, "\n"), "\n")
	fmt.Println(formattedLogo)

	// 调用PrintBoxInfo生成信息框：第一个参数为空字符串（表示顶框无标题），后续为要展示的信息
	PrintBoxInfo("",
		fmt.Sprintf("[Website] %s", website), // 格式化官网信息（拼接标识和地址）
		fmt.Sprintf("[Version] %s", version), // 格式化版本信息（拼接标识和版本号）
	)
}

// PrintGlobalInfo 打印框架运行时的全局状态信息
// 工作原理：
// 1. 获取运行时数据：
//   - 调用syscall.Getpid()获取当前进程的PID（唯一标识当前运行的进程）
//   - 调用mode.GetMode()获取框架运行模式（如debug/release，需导入mode包否则报错）
//
// 2. 生成信息框：调用PrintBoxInfo函数，生成一个“顶框带Global标题”的信息框，填入PID和运行模式
// 执行效果：
// - 屏幕显示一个56字符宽、顶框带"Global"标题的矩形框，例如（假设PID为1234，模式为debug）：
// ┌────────────────────────────────────────────Global─────────────────────────────┐
// | PID: 1234                                                                     |
// | Mode: debug                                                                    |
// └────────────────────────────────────────────────────────────────────────────────┘
// - 标题"Global"在顶框中间位置，左右用横线填充；内部两行分别显示进程ID和运行模式，左对齐
func PrintGlobalInfo() {
	// 调用PrintBoxInfo生成信息框：第一个参数为"Global"（顶框标题），后续为运行时信息
	PrintBoxInfo("Global",
		fmt.Sprintf("PID: %d", syscall.Getpid()), // 格式化PID（拼接标识和进程ID数值）
		fmt.Sprintf("Mode: %s", mode.GetMode()),  // 格式化运行模式（拼接标识和模式字符串，需导入mode包）
	)
}

// PrintBoxInfo 通用的“带边框信息框”生成器（核心工具函数）
// 工作原理：
// 1. 生成顶框：调用buildTopBorder函数，根据传入的name生成“带标题/无标题”的顶部边框
// 2. 生成内容行：遍历infos列表，对每个信息调用buildRowInfo生成“带左右边框的行”，逐行打印
// 3. 生成底框：调用buildBottomBorder函数，生成统一的底部边框，收尾整个信息框
// 核心作用：封装边框生成逻辑，让其他函数无需关注边框细节，只需传入“标题”和“内容”即可生成标准框
// 执行效果：
// - 输入参数示例：name="Test"，infos=["A: 123", "B: 456"]
// - 输出效果：
// ┌─────────────────────────────────────────────Test──────────────────────────────┐
// | A: 123                                                                        |
// | B: 456                                                                        |
// └────────────────────────────────────────────────────────────────────────────────┘
// - 无论传入多少条信息，都能自动生成对应行数的内容，保持框的完整性
func PrintBoxInfo(name string, infos ...string) {
	// 第一步：打印顶部边框（包含标题）
	fmt.Println(buildTopBorder(name))

	// 第二步：遍历所有信息，逐行打印带左右边框的内容
	for _, info := range infos {
		fmt.Println(buildRowInfo(info))
	}

	// 第三步：打印底部边框，完成信息框
	fmt.Println(buildBottomBorder())
}

// buildRowInfo 生成信息框内的“单条内容行”（带左右边框）
// 工作原理：
// 1. 拼接左侧边框：先组合“垂直边框+空格+信息内容”，例如"| A: 123"
// 2. 计算补空格数：
//   - 用utf8.RuneCountInString计算当前字符串的字符数（支持中文，避免多字节导致长度错误）
//   - 总宽度boxWidth - 当前字符串长度 - 1（预留右侧边框的1个字符位置），得到需要补充的空格数
//
// 3. 拼接右侧边框：在补完空格后，添加垂直边框"|"，确保整行长度为boxWidth
// 核心作用：保证每条内容行的宽度统一为56字符，左右对齐，边框整齐
// 执行效果：
// - 输入info="PID: 1234"，生成的行如下（总长度56字符）：
// | PID: 1234                                                                     |
// - 输入info="骗你的其实根本没有网址"，生成的行如下（中文按1字符算，右侧补足够空格）：
// | 骗你的其实根本没有网址                                                       |
func buildRowInfo(info string) string {
	// 第一步：拼接左侧边框和信息（格式："| 信息内容"）
	leftPart := fmt.Sprintf("%s %s", verticalBorder, info)

	// 第二步：计算需要补充的空格数（确保整行宽度为boxWidth）
	// utf8.RuneCountInString：计算字符数（如"中文"算2个，而非6个字节）
	currentLength := utf8.RuneCountInString(leftPart)
	spaceCount := boxWidth - currentLength - 1 // 减1是为右侧边框留位置
	spaces := strings.Repeat(" ", spaceCount)  // 生成对应数量的空格

	// 第三步：拼接右侧边框，形成完整的一行
	fullRow := leftPart + spaces + verticalBorder

	return fullRow
}

// buildTopBorder 生成信息框的“顶部边框”（支持带标题居中）
// 工作原理：
// 1. 计算顶框总可用长度：boxWidth - 左顶边框长度（1） - 右顶边框长度（1） - 标题长度（若有）
//   - 例：boxWidth=56，标题"Global"（6字符），则可用长度=56-1-1-6=48
//
// 2. 计算标题左右横线长度：可用长度/2，让标题居中（若可用长度为奇数，右侧横线多1个，不影响视觉）
// 3. 拼接顶框：左顶边框 + 左侧横线 + 标题（若有） + 右侧横线 + 右顶边框
// 核心作用：根据标题自动调整横线长度，实现标题居中，保证顶框样式统一
// 执行效果：
// - 输入name="Global"（6字符），生成的顶框如下（总长度56字符）：
// ┌────────────────────────────────────────────Global─────────────────────────────┐
//
//	左侧24个横线        标题        右侧24个横线（24+6+24 + 2个边框=56）
//
// - 输入name=""（无标题），生成的顶框如下：
// ┌────────────────────────────────────────────────────────────────────────────────┐
//
//	左侧54个横线（54 + 2个边框=56）
func buildTopBorder(name ...string) string {
	// 处理标题：若传入name，则取第一个元素作为标题；否则标题长度为0
	title := ""
	if len(name) > 0 {
		title = name[0]
	}
	titleLength := utf8.RuneCountInString(title) // 计算标题的字符数（支持中文）

	// 计算顶框的横线总长度（总宽度 - 左右边框 - 标题长度）
	fullLineLength := boxWidth - strLen(leftTopBorder) - strLen(rightTopBorder) - titleLength
	// 标题左侧横线长度（总横线长度的一半，实现居中）
	leftLineLength := fullLineLength / 2
	// 标题右侧横线长度（总横线长度 - 左侧横线长度，处理奇数情况）
	rightLineLength := fullLineLength - leftLineLength

	// 拼接顶框各部分
	topBorder := leftTopBorder                                     // 左顶边框
	topBorder += strings.Repeat(horizontalBorder, leftLineLength)  // 左侧横线
	topBorder += title                                             // 标题（若有）
	topBorder += strings.Repeat(horizontalBorder, rightLineLength) // 右侧横线
	topBorder += rightTopBorder                                    // 右顶边框

	return topBorder
}

// buildBottomBorder 生成信息框的“底部边框”（无标题，纯横线）
// 工作原理：
// 1. 计算底框横线长度：boxWidth - 左底边框长度（1） - 右底边框长度（1）
//   - 例：boxWidth=56，横线长度=56-1-1=54
//
// 2. 拼接底框：左底边框 + 横线 + 右底边框
// 核心作用：作为信息框的收尾，与顶框宽度匹配，保证框的完整性
// 执行效果：
// - 生成的底框固定为56字符宽，如下：
// └────────────────────────────────────────────────────────────────────────────────┘
//
//	54个横线（54 + 2个边框=56）
func buildBottomBorder() string {
	// 计算底框横线长度（总宽度 - 左右底边框）
	lineLength := boxWidth - strLen(leftBottomBorder) - strLen(rightBottomBorder)
	// 拼接底框各部分
	bottomBorder := leftBottomBorder                             // 左底边框
	bottomBorder += strings.Repeat(horizontalBorder, lineLength) // 横线
	bottomBorder += rightBottomBorder                            // 右底边框

	return bottomBorder
}

// strLen 计算字符串的“字符数”（支持UTF-8多字节字符，如中文、特殊符号）
// 工作原理：
// 1. 判断可变参数str是否有值：若有值，取第一个字符串
// 2. 用utf8.RuneCountInString计算该字符串的字符数（而非字节数）
// 3. 若无参数，返回0
// 核心作用：解决中文等多字节字符的长度计算问题（如“中文”算2个字符，而非6个字节），确保边框对齐
// 使用场景：在buildTopBorder、buildBottomBorder中计算边框字符长度（如"┌"算1个字符）
// 执行效果：
// - 输入str="┌"，返回1；输入str="中文"，返回2；输入无参数，返回0
func strLen(str ...string) int {
	// 若有传入字符串，计算第一个字符串的字符数
	if len(str) > 0 {
		return utf8.RuneCountInString(str[0])
	}
	// 若无参数，返回0
	return 0
}
